// ----------------------------------------------------------------------------
// hash.h
// ----------------------------------------------------------------------------
/*
 Description : 各種型からハッシュ値を作成するための基本関数群.
 ----------------------------------------------------------------
 使い方.

 1. 任意のハッシュ関数を選択する. 明示的に指定しない限り、ユーザはどのハッシュ関数をつかうかは気にしなくて良い.
 
 2. 任意の型、もしくは文字列に対してfw::HashValueでハッシュ値を与える. 
 
    uint32_t hogeStrHash = fw::HashValue("Hoge");
 
    HogeStruct hogeInstance;
    uint32_t hogeInstanceHash = fw::HashValue(hogeInstance);

 3. ハッシュ文字列を管理する場合はHashクラスを利用する.
 
 */
// TODO : 静的なハッシュ文字列の解決.
// TODO : 元の文字列を保存しておいて、ハッシュ値から文字列への変換を可能にする.(デバッグ時のみ)
#pragma once
#include <fw/base/runtime/_IMPL/hash_fnv1a.h>
#include <fw/base/runtime/_IMPL/hash_murmur.h>
#include <fw/base/runtime/singleton.h>
#include <fw/base/core/macros.h>
#include <fw/base/core/stdinteger.h>
#include <string.h>
#include <fw/base/stl/stl_string.h>

//namespace FW_DEFAULT_HASH_NAMESPACE = fw::fnv1a;
namespace   FW_DEFAULT_HASH_NAMESPACE = fw::murmur;

namespace fw
{
	extern uint32_t g_lastHashValue32;
	extern uint64_t g_lastHashValue64;
	
	template<typename T> uint32_t HashValue32(const T& value, uint32_t seed=0)
	{
		g_lastHashValue32 = FW_DEFAULT_HASH_NAMESPACE::HashValueInternal32(reinterpret_cast<const void*>(&value),
																		   sizeof(T), seed);
		return g_lastHashValue32;
	}
	
	FW_FORCE_INLINE uint32_t HashValue32(const char* str, uint32_t seed=0)
	{
		g_lastHashValue32 = FW_DEFAULT_HASH_NAMESPACE::HashValueInternal32(reinterpret_cast<const void*>(str),
																		   strlen(str)+1, seed);
		return g_lastHashValue32;
	}
	
	FW_FORCE_INLINE uint32_t HashValue32(const stl::string& str, uint32_t seed=0)
	{
		g_lastHashValue32 = FW_DEFAULT_HASH_NAMESPACE::HashValueInternal32(reinterpret_cast<const void*>(str.c_str()),
																		   str.length()+1, seed);
		return g_lastHashValue32;
	}
	
	FW_FORCE_INLINE uint32_t HashValue32Array(const void* data, size_t dataSize, uint32_t seed=0)
	{
		g_lastHashValue32 = FW_DEFAULT_HASH_NAMESPACE::HashValueInternal32(data, dataSize, seed);
		return g_lastHashValue32;
	}

	template<typename T> uint64_t HashValue64(const T& value, uint64_t seed=0)
	{
		g_lastHashValue64 = FW_DEFAULT_HASH_NAMESPACE::HashValueInternal64(reinterpret_cast<const void*>(&value),
																		   sizeof(T), seed);
		return g_lastHashValue64;
	}
	
	FW_FORCE_INLINE uint64_t HashValue64(const char* str, uint64_t seed=0)
	{
		g_lastHashValue64 = FW_DEFAULT_HASH_NAMESPACE::HashValueInternal64(reinterpret_cast<const void*>(str),
																		   strlen(str)+1, seed);
		return g_lastHashValue64;
	}
	
	FW_FORCE_INLINE uint64_t HashValue64(const stl::string& str, uint64_t seed=0)
	{
		g_lastHashValue64 = FW_DEFAULT_HASH_NAMESPACE::HashValueInternal64(reinterpret_cast<const void*>(str.c_str()),
																		   str.length()+1, seed);
		return g_lastHashValue64;
	}
	
	FW_FORCE_INLINE uint64_t HashValue64Array(const void* data, size_t dataSize, uint64_t seed=0)
	{
		g_lastHashValue64 = FW_DEFAULT_HASH_NAMESPACE::HashValueInternal64(data, dataSize, seed);
		return g_lastHashValue64;
	}
	
    //! 32bit長のハッシュ値.
	class Hash
	{
	private:
		uint32_t	m_value;
	public:
		Hash(const char* text);
		Hash(uint32_t value);
		Hash();
		
		operator const uint32_t() const;
		operator const bool() const;
		bool operator==(const Hash& other) const;
	}; // class Hash

    //! 64bit長のハッシュ値.
	class HashL
	{
	private:
		uint64_t	m_value;
	public:
		HashL(const char* text);
		HashL(uint64_t value);
		HashL();
		
		operator const uint64_t() const;
		operator const bool() const;
		bool operator==(const HashL& other) const;
	}; // class HashL
    
    //! 文字列へのポインタを所有するハッシュ値.
    template<typename hash_context, typename hash_base>class HashStringT : public hash_base
    {
    public:
        const char* m_text;
    public:
        HashStringT(const char* text);
        HashStringT();
        
        const char* const GetName() const
        {
            return m_text;
        }
    }; // class HashStringT

    //! 文字列と32bitハッシュ値を保持しておく為のコンテキストのデフォルト実装.
    class DefaultHashContextImpl;
    class DefaultHashContext : private Singleton<DefaultHashContext>
    {
    private:
        DefaultHashContextImpl* m_impl;
        
    public:
         DefaultHashContext();
        ~DefaultHashContext();
        
        const char*     GetBaseStringPointer(uint32_t value, const char* ptr);
    }; // class DefaultHashContext

    //! 文字列と64bitハッシュ値を保持しておく為のコンテキストのデフォルト実装.
    class DefaultHashLContextImpl;
    class DefaultHashLContext : private Singleton<DefaultHashLContext>
    {
    private:
        DefaultHashLContextImpl* m_impl;
        
    public:
         DefaultHashLContext();
        ~DefaultHashLContext();
        
        const char*     GetBaseStringPointer(uint64_t value, const char* ptr);
    }; // class DefaultHashLContext
    
    typedef HashStringT<DefaultHashContext,  Hash>  HashString;
    typedef HashStringT<DefaultHashLContext, HashL> HashStringL;
    
} // namespace fw

#define FW_HASH(str) fw::HashValue(str)
